/*
 *   Copyright 2021 zzh
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */

package com.aduib.boot.logging.filter;

import com.aduib.boot.common.servlet.CachedContentServletReqWrapper;
import com.aduib.boot.common.servlet.CachedContentServletRespWrapper;
import com.aduib.boot.common.util.WebUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @description: AbstractLogFilter
 * @author: zzh
 * @date: 2021/9/15 16:39
 */
public abstract class AbstractLogFilter extends OncePerRequestFilter {

  @Override
  protected void doFilterInternal(HttpServletRequest request,
      HttpServletResponse response, FilterChain filterChain)
      throws ServletException, IOException {

    // 包装request，以保证可以重复读取body 但不对文件上传请求body进行处理
    HttpServletRequest requestWrapper;
    if (WebUtils.isMultipartContent(request)) {
      requestWrapper = request;
    }
    else {
      requestWrapper = new CachedContentServletReqWrapper(request);
    }
    // 包装 response，便于重复获取 body
    CachedContentServletRespWrapper responseWrapper = new CachedContentServletRespWrapper(response);
    // 开始时间
    Throwable myThrowable = null;
    boolean enabledDoFilter = false;
    try {
      enabledDoFilter = beforeRequest(requestWrapper, responseWrapper, filterChain);
      if (enabledDoFilter) {
        filterChain.doFilter(requestWrapper, responseWrapper);
      }
    } catch (Throwable throwable) {
      // 记录外抛异常
      myThrowable = throwable;
      throw throwable;
    }
    finally {
      if (enabledDoFilter) {
        Throwable throwable =
            (Throwable) requestWrapper.getAttribute("javax.servlet.error.exception");
        if (throwable != null) {
          myThrowable = throwable;
        }
        afterRequest(requestWrapper, responseWrapper, myThrowable);
      }
    }
  }

  /**
   * @param request
   * @param response
   * @param filterChain
   * @throws ServletException
   * @throws IOException
   */
  public abstract boolean beforeRequest(HttpServletRequest request,
      HttpServletResponse response, FilterChain filterChain)
      throws ServletException, IOException;

  /**
   *
   * @param request
   * @param response
   * @param throwable
   * @throws ServletException
   * @throws IOException
   */
  public abstract void afterRequest(HttpServletRequest request,
      HttpServletResponse response, Throwable throwable)
      throws ServletException, IOException;
}
